package com.ayh.campusfun.common.core.jwt;


import com.ayh.campusfun.common.exception.http.ForbiddenException;
import com.ayh.campusfun.entity.Users;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ayh
 * @create 2021/3/24 0024 12:50
 * JWT工具类
 */

@Component
public class JWTUtils {

    //荷载claim的名称
    private static final String CLAIM_KEY_USERNAME = "sub";
    //荷载的创建时间
    private static final String CLAIM_KEY_CREATED = "created";
    //荷载的用户id
    private static final String CLAIM_KEY_UID = "uid";
    private static final String CLAIM_KEY_AVATAR = "avatar";

    // jwt令牌的秘钥
    @Value("${jwt.secret}")
    private String secret;
    //jwt的实效时间
    @Value("${jwt.expiration}")
    private Long expiration;

    @Value("${jwt.token-header}")
    private String toKenHeader;

    @Value("${jwt.token-head}")
    private String toKenHead;

    /**
     * 根据用户信息生成token
     *
     * @param user
     * @return
     */
    public String getToken(Users user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, user.getNickName());
        claims.put(CLAIM_KEY_UID, user.getUid());
        claims.put(CLAIM_KEY_AVATAR, user.getAvatarUrl());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateTokenByClaims(claims);
    }

    /**
     * 根据荷载生成JWTToken
     *
     * @param claims
     * @return
     */
    private String generateTokenByClaims(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpiration())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }


    /**
     * 从token获取用户信息
     * @param token
     * @return
     */
    public String getUserId(String token){
        return (String) getClaimsFromToken(token).get("uid");
    }
    public String getUserName(String token){
        return (String) getClaimsFromToken(token).get("sub");
    }

    public String getUserAvatar(String token){
        return (String) getClaimsFromToken(token).get("avatar");
    }



    /**
     * token是否有效
     * @param token
     * @param user
     * @return
     */
    public Boolean validateToken(String token,Users user){
//        TODO 修改验证方式
        Claims userClaims = getClaimsFromToken(token);
        return userClaims.get(CLAIM_KEY_UID).equals(user.getUid()) && tokenExpiredStatus(token);
    }

    /**
     * 判断token是否可以被刷新
     * @param token
     * @return
     */
    public Boolean canRefresh(String token){
        return tokenExpiredStatus(token);
    }

    /**
     * 刷新token
     * @param token
     * @return
     */
    public String refreshToken(String token){
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED,new Date());
        return generateTokenByClaims(claims);
    }

    /**
     * 判断token是否失效
     * @param token
     * @return
     */
    public boolean tokenExpiredStatus(String token) {
        Date expireDate = getExpiredDateFromToken(token);
        //如果token有效的时间在当前时间之前就表示实效
        return !expireDate.before(new Date());
    }

    /**
     * 从token中获取实效时间
     * @param token
     * @return
     */
    public Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据token获取荷载
     * @param token
     * @return
     */
    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 生成token实效时间
     *
     * @return
     */
    private Date generateExpiration() {
        // 当前时间+配置时间
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    public void verifyToken(String token){
        Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
    }

    public String getUidFromRequest(HttpServletRequest request){
        String authorization = request.getHeader(toKenHeader);
        if (null == authorization)
            throw new ForbiddenException(60009);
        String token = authorization.replaceAll(toKenHead,"").trim();
//        验证token是否有效
        this.verifyToken(token);
        return this.getUserId(token);
    }

    public String getNameFromRequest(HttpServletRequest request){
        String authorization = request.getHeader(toKenHeader);
        if (null == authorization)
            throw new ForbiddenException(60009);
        String token = authorization.replaceAll(toKenHead,"").trim();
//        验证token是否有效
        this.verifyToken(token);
        return this.getUserName(token);
    }

    public String getAvatarFromRequest(HttpServletRequest request){

        String authorization = request.getHeader(toKenHeader);
        if (null == authorization)
            throw new ForbiddenException(60009);
        String token = authorization.replaceAll(toKenHead,"").trim();
//        验证token是否有效
        this.verifyToken(token);
        return this.getUserAvatar(token);

    }
    public Users getUserFromRequest(HttpServletRequest request){
        String authorization = request.getHeader(toKenHeader);
        if (null == authorization)
            throw new ForbiddenException(60009);
        String token = authorization.replaceAll(toKenHead,"").trim();
//        验证token是否有效
        this.verifyToken(token);
        Claims claimsFromToken = this.getClaimsFromToken(token);
        claimsFromToken.put("nickName",claimsFromToken.get(CLAIM_KEY_USERNAME));
        ObjectMapper mapper = new ObjectMapper();
        return mapper.convertValue(claimsFromToken, Users.class);
    }

    public String getTokenFromRequest(HttpServletRequest request){

        String authorization = request.getHeader(toKenHeader);
        if (null == authorization)
            throw new ForbiddenException(60009);
        String token = authorization.replaceAll(toKenHead,"").trim();
//        验证token是否有效
        this.verifyToken(token);
        return token;
    }

}
